home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-06-15 | 18.2 KB | 681 lines | [TEXT/MPS ] |
- {
- File Cookie.p
-
- Programmer: D. Jay Newman 1/27/89
- DA which does Fortune Cookies.
- I release this into the public domain.
-
- The data file with all the cookie information must be in your
- active system folder, and the name is specified in an STR#
- resource (right now it is "Fortunes").
-
- The data format of the fortune cookie file is the following:
- Number of Cookies: LONGINT
- List of offsets: ARRAY OF LONGINT (offsets from the
- start of the TEXT)
- Offset of EOF: LONGINT
- Text of cookies: Text (no separators between cookies)
-
- This means 3 file reads at the start, and 2 more for each additional
- cookie is wanted; the speed is pretty good on my Mac II's hard disk,
- but if it becomes a problem, well, this isn't a necessary program.
-
- Things to do later: I would like to add some data compression, but I
- haven't gotten around to it; I would also like to write a cookie editor,
- rather than the tool to convert a text file into a cookie file.
- }
-
- {$R-} { No range checking }
-
- UNIT Memory;
-
- INTERFACE
-
- USES
- MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf;
-
-
- FUNCTION DRVROpen (ctlPB: ParmBlkPtr; dCtl: DCtlPtr): OSErr;
- FUNCTION DRVRControl (ctlPB: ParmBlkPtr; dCtl: DCtlPtr): OSErr;
- FUNCTION DRVRStatus (ctlPB: ParmBlkPtr; dCtl: DCtlPtr): OSErr;
- FUNCTION DRVRPrime (ctlPB: ParmBlkPtr; dCtl: DCtlPtr): OSErr;
- FUNCTION DRVRClose (ctlPB: ParmBlkPtr; dCtl: DCtlPtr): OSErr;
-
-
- IMPLEMENTATION
-
- TYPE
- EventPtr = ^EventRecord;
- trix = RECORD {Needed for some coercive behavior }
- CASE Boolean of
- TRUE: (FayWray: ARRAY[0..10] OF Integer);
- FALSE: (Away: EventPtr);
- END;
-
- MyDataRec = RECORD
- numCookies: LONGINT; {number of fortune cookies in file}
- cookRefNum: INTEGER; {the refNum of the cookie file}
- theTEH: TEHandle; {Handle to TE record for the displayed cookie}
- qSeed: LONGINT; {Seed for random number generator}
- theButton: ControlHandle; {Remember the button}
- theScroll: ControlHandle; {And don't forget the bar}
- theRect: Rect; {Original rects for TEHandle}
- pRect: Rect; {Comparison portRect: if changed, fix stuff}
- END;
-
- MyDataPtr = ^MyDataRec;
- MyDataHndl = ^MyDataPtr;
-
- RectPtr = ^Rect;
- RectHandle = ^RectPtr;
-
- CONST
- kScrollWidth = 16;
-
- kMargin = 5;
- kRightMarg = kScrollWidth;
- kBotMarg = 43;
-
- kButtonLeft = 100; {80 from right edge of window}
- kButtonRight = 30; {10 from right edge of window}
- kButtonTop = 38;
- kButtonBottom = 18;
-
- kMaxRandNum = $7FFFFFFF; {The maximum random number}
- kMinRandNum = 0; {The smallest possible random number}
-
-
- FUNCTION RsrcID(dCtl: DCtlPtr): Integer;
- BEGIN
- RsrcID := (BOR($C000,(BSL(BNOT(dCtl^.dCtlRefNum),5))));
- END;
-
-
- {Get a longint stored in a file at a given position from the begining; if
- position = -1, then do not set the position}
- FUNCTION GetLongInt (fRefNum: INTEGER; position: LONGINT; VAR theNum: LONGINT): OSErr;
- VAR
- aLen: LONGINT; {the length off the read}
- err: OSErr;
- BEGIN
- IF position >= 0 THEN
- err := SetFPos (fRefNum, FsFromStart, position);
-
- aLen := SizeOf (LONGINT);
- GetLongInt := FSRead (fRefNum, aLen, @theNum);
- END;
-
-
- {A simple replacement for the random function, to get around having to do
- weird things to the QuickDraw globals to effect the global randSeed under
- MultiFinder}
- FUNCTION Rndom (seed: LONGINT): LONGINT;
- BEGIN
- (*
- Rndom := (seed * 16807) MOD 2147483647;
- *)
- Rndom := BAND (seed * 452807053, $7FFFFFFF);
- END;
-
-
- {Set the values for the scroll bar, depending upon the TE stuff}
- PROCEDURE SetScrollValues (aTEH: TEHandle; scrollBar: ControlHandle);
- VAR
- lines: INTEGER; {Number of lines of text}
- max: INTEGER; {Max value for control}
- BEGIN
- WITH aTEH^^ DO
- BEGIN
- lines := nLines;
- max := lines - ((viewRect.bottom - viewRect.top) DIV lineHeight);
- END;
-
- IF max < 0 THEN max := 0;
- SetCtlMax (scrollBar, max);
- SetCtlValue (scrollBar, 0);
- END;
-
-
- FUNCTION GetCookie (myHandle: MyDataHndl): BOOLEAN;
- VAR
- nCookies: LONGINT; {Number of cookies in file}
- theRefNum: INTEGER; {Ref number of cookie data file}
- theCookie: LONGINT; {The index of the cookie choosen}
- cookieStart: LONGINT; {Start of first cookie}
- cookiePos: LONGINT; {Offset of cookie choosen}
- cookLen: LONGINT; {Length of cookie}
- theResult: OSErr; {A container for the results of I/O operations}
- aLong: LONGINT; {A LONGINT container for general use}
- theText: Handle; {Handle for the text of the cookie}
- theRndNum: LONGINT; {Random number}
- cookieTEH: TEHandle; {Handle to TE record for displayed cookie}
- BEGIN
- {Get the information from the handle}
- WITH myHandle^^ DO
- BEGIN
- nCookies := numCookies;
- theRefNum := cookRefNum;
- cookieTEH := theTEH;
- theRndNum := qSeed;
- END;
-
- cookieStart := (nCookies + 2) * SizeOf (LONGINT); {Start of cookie text in file}
-
- theCookie := nCookies + 1; {Make it loop at least once}
-
- theRndNum := Rndom (theRndNum);
- myHandle^^.qSeed := theRndNum; {Remember random seed}
-
- theCookie := theRndNum DIV (kMaxRandNum DIV nCookies);
-
- WHILE (theCookie > nCookies) OR (theCookie < 0) DO
- BEGIN
- theRndNum := Rndom (theRndNum);
- END;
-
- {Read the index of the choosen cookie}
- aLong := theCookie * SizeOf (LONGINT);
- theResult := GetLongInt (theRefNum, aLong, cookiePos);
-
- {Get the index of the following cookie}
- theResult := GetLongInt (theRefNum, aLong + SizeOf (LONGINT), cookLen);
- cookLen := cookLen - cookiePos;
-
- theResult := SetFPos (theRefNum, FSFromStart, cookieStart + cookiePos);
-
- theText := cookieTEH^^.hText;
- SetHandleSize (theText, cookLen);
-
- HLock (theText);
- theResult := FSRead (theRefNum, cookLen, theText^); {Read the cookie}
- HUnlock (theText);
-
- cookieTEH^^.viewRect := myHandle^^.theRect;
- cookieTEH^^.destRect := myHandle^^.theRect;
- TECalText (cookieTEH);
-
- {Remember, set the new maximum for the scrollbar}
- SetScrollValues (cookieTEH, myHandle^^.theScroll);
-
- GetCookie := TRUE;
- END;
-
-
- FUNCTION ButtonPosition (r: Rect): Rect;
- BEGIN
- {Position the button relative to the portRect}
- r.top := r.bottom - kButtonTop;
- r.bottom := r.bottom - kButtonBottom;
- r.left := r.right - kButtonLeft;
- r.right := r.right - kButtonRight;
-
- ButtonPosition := r;
- END;
-
-
- FUNCTION TEPosition (r: Rect; aTEH: TEHandle): Rect;
- BEGIN
- {Position the TE field relative to the portRect}
- r.bottom := r.bottom - kBotMarg; {Don't hide button}
- r.bottom := r.bottom -
- ((r.bottom - r.top + 3) MOD aTEH^^.lineHeight);
- r.right := r.right - kRightMarg; {Standard scroll bar width}
- InsetRect (r, 5, 5);
-
- TEPosition := r;
- END;
-
-
- FUNCTION SBarPosition (r: Rect): Rect;
- BEGIN
- r.left := r.right - kScrollWidth + 1;
- r.right := r.right + 1;
- r.top := r.top - 1;
- r.bottom := r.bottom - kScrollWidth + 2;
-
- SBarPosition := r;
- END;
-
-
- FUNCTION DRVROpen (ctlPB: ParmBlkPtr; dCtl: DCtlPtr): OSErr;
-
- {Open the cookie file in the system folder}
- FUNCTION OpenCookieFile (fileName: Str255; VAR fRefNum: INTEGER): OSErr;
- VAR
- aHPB: HParamBlockRec; {for the PBHGerVInfo call}
- err: OSErr; {the result of the call}
- xErr: OSErr; {a throw-away error}
- oldVol: INTEGER; {save old volume}
- ioWDDirID: LONGINT;
- BEGIN
- WITH aHPB DO
- BEGIN
- ioCompletion := NIL;
- ioNamePtr := NIL; {there because something is necessary}
- ioVRefNum := 0; {for default volume}
- ioVolIndex := 0; {not an indexed call}
- END;
- err := PBHGetVInfo (@aHPB, FALSE);
-
- WITH aHPB DO
- BEGIN
- ioCompletion := NIL;
- ioNamePtr := NIL;
- ioVRefNum := 0;
- ioWDDirID := aHPB.ioVFndrInfo [1];
- END;
-
- err := GetVol (NIL, OldVol);
- err := PBHSetVol (@aHPB, FALSE); {Get to blessed folder}
-
- IF err = 0 THEN
- BEGIN
- err := FSOpen (fileName, 0, fRefNum);
- xErr := SetVol (NIL, oldVol); {Restore old current folder}
- END;
-
- OpenCookieFile := err;
- END;
-
-
- FUNCTION GetRandomSeed: LONGINT;
- VAR
- secs: LONGINT; {A bit risque, but what the heck}
- BEGIN
- GetDateTime (secs); {A lot of seconds}
-
- secs := BXOR (secs, TickCount);
- IF (secs MOD 2) = 0 THEN
- secs := secs + 1; {Always have odd seed, not a bad one}
-
- GetRandomSeed := BXOR (secs, TickCount);
- END;
-
-
- {Remember the last position of the window, and if not, fake it}
- PROCEDURE PutWindowInPlace;
- VAR
- curRes: INTEGER; {Ref num for current resource file}
- r: Rect; {Rect for window}
- rHandle: RectHandle; {Handle for resource}
- BEGIN
- curRes := CurResFile; {Save current resource file}
- IF curRes <> 0 THEN
- UseResFile (0); {Use system file}
-
- rHandle := RectHandle (GetResource ('WhAt', RsrcID (dCtl)));
- IF rHandle <> NIL THEN
- r := rHandle^^
- ELSE
- SetRect (r, 40, 40, 200, 100);
-
- IF curRes <> 0 THEN {Be nice and return resource file}
- UseResFile (curRes);
-
- MoveWindow (dCtl^.dCtlWindow, r.left, r.top, FALSE);
- SizeWindow (dCtl^.dCtlWindow, r.right - r.left, r.bottom - r.top, FALSE);
- END;
-
-
- VAR
- SavePort: GrafPtr; {place to save old grafPort}
- nCookies: LONGINT; {number of cookies in file}
- myWindow: WindowPtr; {window pointer}
- cookName: Str255; {name of cookie file}
- cRefNum: INTEGER; {RefNum for cookie file}
- theResult: OSErr; {stuff to bypass error checking, add later}
- aTEH: TEHandle; {TE handle to display stuff}
- txRect: Rect; {rectangle for TE}
- myHandle: MyDataHndl; {handle to device storage}
- aControl: ControlHandle; {Control handle to create controls}
- r: Rect; {Rect for the window (and button)}
- aHandle: Handle; {A handle to avoid problems with memory}
- BEGIN {DRVROpen}
- IF dCtl^.dCtlWindow = NIL THEN
- BEGIN
- GetPort (SavePort);
-
- {Find the cookie file name, then get the number of cookies}
- GetIndString(cookName, RsrcID (dCtl), 1);
-
- theResult := OpenCookieFile (cookName, cRefNum);
- IF theResult <> noErr THEN
- BEGIN
- DRVROpen := theResult;
- EXIT (DRVROpen);
- END;
-
- {Allocate storage}
- myHandle := MyDataHndl (NewHandle (SizeOf (MyDataRec)));
-
- dCtl^.dCtlStorage := Handle (myHandle);
-
- myHandle^^.qSeed := GetRandomSeed; {Initialize random number gen}
-
- myWindow := GetNewWindow (RsrcID(dCtl), NIL, POINTER(-1));
- windowpeek(myWindow)^.WindowKind := dCtl^.dCtlRefNum;
- {show a DA owns this window}
- dCtl^.dCtlWindow := myWindow; {let the desk manager know too }
-
- PutWindowInPlace;
-
- ShowWindow (myWindow);
- SetPort (myWindow); {Set up port parameters}
-
- myHandle^^.pRect := myWindow^.portRect; {Save for now}
-
- r := ButtonPosition (myWindow^.portRect); {Set up button's rect}
- aControl := NewControl (myWindow, r, 'Another', TRUE,
- 0, 0, 0, pushButProc, 0); {Make the button}
- myHandle^^.theButton := aControl;
-
- myHandle^^.cookRefNum := cRefNum;
-
- {Get number of cookies}
- theResult := GetLongInt (cRefNum, 0, nCookies);
- myHandle ^^.numCookies := nCookies;
-
- {Set up the font used}
- TextFont (applFont);
- TextFace ([]);
- TextMode (srcCopy);
- TextSize (12);
-
- {Initialize theTEH}
- aTEH := TENew (r, r); {Create with any rect}
- r := TEPosition (myWindow^.portRect, aTEH); {Now calculate real rects}
-
- myHandle^^.theTEH := aTEH;
- myHandle^^.theRect := r;
-
- r := SBarPosition (myWindow^.portRect); {Set up scroll bars}
-
- aControl := NewControl (myWindow, r, '', TRUE,
- 0, 0, 32767, scrollBarProc, Ord4 (aTEH)); {Make the scroll bar}
- myHandle^^.theScroll := aControl;
-
- {Get first cookie}
- IF GetCookie (myHandle) THEN;
-
- SetPort (SavePort);
- END;
- DRVROpen := noErr;
- END;
-
-
- FUNCTION DRVRClose (ctlPB: ParmBlkPtr; dCtl: DCtlPtr): OSErr;
- VAR
- myHandle: MyDataHndl;
- anOSErr: OSErr;
- refNum: INTEGER;
- rHandle: RectHandle;
- r: Rect;
- p: Point;
- resID: INTEGER;
- BEGIN
- IF dCtl^.dCtlWindow <> NIL THEN
- BEGIN
- myHandle := MyDataHndl (dCtl^.dCtlStorage);
-
- refNum := CurResFile;
- IF refNum <> 0 THEN
- UseResFile (0); {Use system file}
-
- resID := RsrcID (dCtl);
- rHandle := RectHandle (GetResource ('WhAt', resID));
-
- r := dCtl^.dCtlWindow^.portRect; {Get position}
- p := dCtl^.dCtlWindow^.portBits.bounds.topLeft;
-
- r.top := r.top - p.v; {Convert to global}
- r.left := r.left - p.h;
- r.bottom := r.bottom - p.v;
- r.right := r.right - p.h;
-
- IF rHandle <> NIL THEN
- BEGIN
- IF NOT EqualRect (rHandle^^, r) THEN
- BEGIN
- rHandle^^ := r;
- ChangedResource (Handle (rHandle));
- END;
- END
- ELSE
- BEGIN
- rHandle := RectHandle (NewHandle (SizeOf (Rect)));
- rHandle^^ := r;
- AddResource (Handle (rHandle), 'WhAt', resID, 'Cook''s WhereAt');
- END;
-
- IF refNum <> 0 THEN {Be nice and return resource file}
- UseResFile (refNum);
-
- anOSErr := FSClose (myHandle^^.cookRefNum); {Close cookie file}
-
- TEDispose (myHandle^^.theTEH); {Get rid of TEHandle;
- it gets rid of hText}
- DisposHandle (Handle (myHandle)); {Get rid of storage}
- DisposeWindow (WindowPtr(dCtl^.dCtlWindow)); {Get rid of window}
- dCtl^.dCtlWindow := NIL;
- END;
- DRVRClose := NOErr;
- END;
-
-
- PROCEDURE MyScrollProc (control: ControlHandle; part: INTEGER);
- VAR
- amount: INTEGER;
- aTEH: TEHandle;
- value: INTEGER;
- max: INTEGER;
- BEGIN
- IF part <> 0 THEN
- BEGIN
- aTEH := TEHandle (GetCRefCon (control));
-
- CASE part OF
- inUpButton, inDownButton:
- amount := 1;
-
- inPageUp, inPageDown:
- WITH aTEH^^ DO
- amount := (viewRect.bottom - viewRect.top) DIV lineHeight;
- END;
-
- IF (part = inDownButton) OR (part = inPageDown) THEN
- amount := -amount;
-
- {Set the actual amount, taking into account min and max}
- value := GetCtlValue (control);
- max := GetCtlMax (control);
- amount := value - amount;
-
- IF amount < 0 THEN
- amount := 0
- ELSE IF amount > max THEN
- amount := max;
-
- SetCtlValue (control, amount);
- amount := value - amount; {Make this be the amount changed}
-
- IF amount <> 0 THEN
- TEScroll (0, amount * aTEH^^.lineHeight, aTEH); {Actually scroll}
- END;
- END;
-
-
- FUNCTION DRVRControl(ctlPB: ParmBlkPtr; dCtl: DCtlPtr): OSErr;
- VAR
- eventAt: EventPtr; {Pointer to our event}
- myHandle: MyDataHndl; {Handle to our personal data}
- aButton: ControlHandle; {Our button}
- p: Point; {Point clicked at for button}
- theText: Handle; {Text for copying}
- aTEH: TEHandle; {Handle to the cookie TERecord}
-
- PROCEDURE DrawWindow;
- VAR
- r: Rect;
- BEGIN {DrawWindow}
- {
- If the saved portRect (myHandle^^.pRect) doesn't equal the actual
- portRect, then we have to recalculate the text and button positions
- }
- IF NOT EqualRect (myHandle^^.pRect, dCtl^.dCtlWindow^.portRect) THEN
- BEGIN
- r := dCtl^.dCtlWindow^.portRect;
- myHandle^^.pRect := r;
- EraseRect (r);
- myHandle^^.theButton^^.contrlRect := ButtonPosition (r);
- myHandle^^.theScroll^^.contrlRect := SBarPosition (r);
- r := TEPosition (r, aTEH);
- aTEH^^.viewRect := r;
- aTEH^^.destRect := r;
- myHandle^^.theRect := r; {Save rect for later}
- TECalText (aTEH);
- SetScrollValues (aTEH, myHandle^^.theScroll);
- END
- ELSE
- EraseRect (aTEH^^.destRect);
-
- TEUpdate (aTEH^^.destRect, aTEH); {Draw text}
-
- DrawControls (dCtl^.dCtlWindow); {Draw button and SBar}
- DrawGrowIcon (dCtl^.dCtlWindow); {Draw the grow Icon}
- END; {DrawWindow}
-
-
- {Do whatever is necessary for handling controls}
- PROCEDURE CheckControls (gp: Point);
- VAR
- aWindow: WindowPtr; {Pointer to window, hopefully mine}
- aControl: ControlHandle; {Control handle for FindControl}
- aPart: INTEGER; {Which part of window or control}
- r: Rect; {Used to pass min/max window sizes}
- newSize: LONGINT; {passed back from GrowWindow}
- value: INTEGER; {The value of the scrollbar}
- p: Point; {The point in local coords}
- BEGIN
- p := gp;
- GlobalToLocal (p);
-
- r := dCtl^.dCtlWindow^.portRect;
- r.top := r.bottom - 16;
- r.left := r.right - 16;
-
- IF PtInRect (p, r) THEN
- BEGIN
- {Grow the window}
- aWindow := dCtl^.dCtlWindow;
- SetRect (r, 100, 100, 640, 400);
- newSize := GrowWindow (aWindow, gp, r);
- IF newSize <> 0 THEN
- BEGIN
- SizeWindow (aWindow, LoWrd (newSize),
- HiWrd (newSize), FALSE);
- InvalRect (aWindow^.portRect);
- END;
- END
-
- ELSE
- BEGIN
- aPart := FindControl (p, dCtl^.dCtlWindow, aControl);
-
- IF aPart <> 0 THEN
- BEGIN {Yes, was a control}
- IF GetCRefCon (aControl) = 0 THEN {Is the button!}
- BEGIN
- IF TrackControl (aControl, p, NIL) <> 0 THEN
- BEGIN {Yes, button clicked}
- IF GetCookie (myHandle) THEN;
- InvalRect (dCtl^.dCtlWindow^.portRect);
- END;
- END
- ELSE
- BEGIN {Must be scroll bar}
- IF aPart = inThumb THEN {Handle thumb as special case}
- BEGIN
- value := GetCtlValue (aControl);
- IF TrackControl (aControl, p, NIL) <> 0 THEN {If 0, do nothing}
- BEGIN
- value := value - GetCtlValue (aControl);
- IF value <> 0 THEN
- TEScroll (0, value * aTEH^^.lineHeight, aTEH);
- END;
- END
- ELSE
- value := TrackControl (aControl, p, @myScrollProc);
- END;
- END;
- END;
- END;
-
-
- PROCEDURE DoAccEvent;
- BEGIN
- CASE eventAt^.what OF
- UpdateEvt: {Update Event}
- BEGIN
- BeginUpdate (WindowPtr(eventAt^.message));
- DrawWindow;
- EndUpdate (WindowPtr(eventAt^.message));
- END;
-
- mouseDown: {MouseDown Event, might be control}
- BEGIN
- CheckControls (eventAt^.where);
- END;
-
- keyDown, autoKey:
- BEGIN
- SysBeep (0);
- END;
- END; {accEvent}
- END;
-
-
- PROCEDURE DoCopy;
- BEGIN
- IF ZeroScrap <> 0 THEN; {Returns a LONGINT}
- theText := myHandle^^.theTEH^^.hText;
- HLock (theText);
- IF PutScrap (GetHandleSize (theText), 'TEXT', theText^) <> 0 THEN;
- HUnlock (theText);
- END;
-
-
- BEGIN {DRVRControl}
- SetPort(GrafPtr(dCtl^.dCtlWindow));
- myHandle := MyDataHndl (dCtl^.dCtlStorage);
- aTEH := myHandle^^.theTEH;
-
- CASE ctlPB^.csCode OF
- accEvent:
- BEGIN
- eventAt := trix(ctlPB^.CSParam).Away; {get the event pointer}
- DoAccEvent;
- END;
-
- accCopy, accCut:
- BEGIN
- DoCopy;
- END;
- END; {CASE}
- DRVRControl := NoErr;
- END; {DRVRControl}
-
-
- FUNCTION DRVRPrime (ctlPB: ParmBlkPtr; dCtl: DCtlPtr): OSErr;
- BEGIN
- DRVRPrime := NoErr;
- END;
-
- FUNCTION DRVRStatus (ctlPB: ParmBlkPtr; dCtl: DCtlPtr): OSErr;
- BEGIN
- DRVRStatus := NoErr;
- END;
-
-
- END. {UNIT Cookie}
-
-